package cn.alpha.workflow.controller;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.servlet.http.HttpServletResponse;

import org.activiti.bpmn.model.BpmnModel;
import org.activiti.engine.ProcessEngineConfiguration;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricDetail;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.history.HistoricProcessInstanceQuery;
import org.activiti.engine.identity.User;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.impl.pvm.PvmTransition;
import org.activiti.engine.impl.pvm.process.ActivityImpl;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.runtime.ProcessInstanceQuery;
import org.activiti.engine.task.Comment;
import org.activiti.engine.task.Task;
import org.activiti.image.ProcessDiagramGenerator;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import cn.alpha.workflow.service.impl.UserService;
import cn.alpha.workflow.service.impl.WorkflowTraceService;
import cn.alpha.workflow.vo.DTRequestParam;
import cn.alpha.workflow.vo.DTResponseData;
import cn.ffcs.shequ.bo.Result;

@Controller("procinstController")
public class ProcinstController extends AbstractController 
{
	@Autowired
	private ProcessEngineConfiguration processEngineConfiguration;
	
	@Autowired
	private WorkflowTraceService wfTranceService;
	
	@Autowired
	private UserService userService;
	
	@RequestMapping(value = "/procinst/info")
    @ResponseBody
    public Map<String,Object> procinstInfo(String procinstId)
	{
		Map<String,Object> res=new HashMap<String, Object>();

		// 查询所有的历史活动记录
        List<HistoricActivityInstance> actInsts = historyService.createHistoricActivityInstanceQuery()
        		.processInstanceId(procinstId).activityType("userTask").list();
        HistoricProcessInstance procinstH = historyService.createHistoricProcessInstanceQuery().processInstanceId(procinstId).singleResult();
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(procinstH.getProcessDefinitionId()).singleResult();
        
        //人员信息
        Set<String> userIds=new HashSet<String>();
        for(HistoricActivityInstance e:actInsts)
       		userIds.add(e.getAssignee());
        Map<String,User> idUser=userService.getUserByIdsMap(userIds);

        //评论信息
        Map<String,Comment> idComment=new HashMap<String, Comment>();
		List<Comment> comments=taskService.getProcessInstanceComments(procinstId);
		for(Comment c:comments)
			idComment.put(c.getTaskId(), c);
		
        List<Map<String,Object>> activities=new ArrayList<Map<String,Object>>();
        Map<String,Object> activiti;
        User user;
        Comment comment;
        for(HistoricActivityInstance e:actInsts)
        {
        	activiti=new HashMap<String, Object>();
        	activiti.put("activityName", e.getActivityName());
        	user=idUser.get(e.getAssignee());
        	activiti.put("assignee", user==null?"":user.getFirstName());
        	activiti.put("startTime", e.getStartTime());
        	activiti.put("endTime", e.getEndTime());
        	activiti.put("durationInMillis", e.getDurationInMillis());
        	comment=idComment.get(e.getTaskId());
        	activiti.put("comment", comment==null?"":comment.getFullMessage());
        	activities.add(activiti);
        }
        
        res.put("activities", activities);
        res.put("processDefinitionName", processDefinition.getName());
		return res;
    }
	
	@RequestMapping(value = "/procinst/trace/info")
    @ResponseBody
    public List<Map<String, Object>> traceProcessInfo(String procinstId) throws Exception 
	{
        List<Map<String, Object>> activityInfos = wfTranceService.traceProcess(procinstId);
        return activityInfos;
    }
	
	@RequestMapping(value = "/procinst/trace/image")
    public void traceProcessImage(String procinstId, HttpServletResponse response) throws Exception 
	{
        ProcessInstance procinst = runtimeService.createProcessInstanceQuery().processInstanceId(procinstId).singleResult();
        InputStream imageStream;
        if(procinst!=null)
        {//运行时的流程实例
        	 BpmnModel bpmnModel = repositoryService.getBpmnModel(procinst.getProcessDefinitionId());
             ProcessDefinitionEntity processDefinition = (ProcessDefinitionEntity) repositoryService.createProcessDefinitionQuery().processDefinitionId(procinst.getProcessDefinitionId()).singleResult();
             List<String> activeActivityIds = runtimeService.getActiveActivityIds(procinstId);
             ProcessDiagramGenerator diagramGenerator = processEngineConfiguration.getProcessDiagramGenerator();
             List<String> highLightedFlows = getHighLightedFlows(processDefinition, procinst.getId());
             imageStream =diagramGenerator.generateDiagram(bpmnModel, "png", activeActivityIds, highLightedFlows,
             		processEngineConfiguration.getActivityFontName(),processEngineConfiguration.getLabelFontName(),null,1.0);
        }
        else
        {//已结束的流程实例
        	HistoricProcessInstance procinstH=historyService.createHistoricProcessInstanceQuery().processInstanceId(procinstId).singleResult();
        	ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                    .processDefinitionId(procinstH.getProcessDefinitionId()).singleResult();
        	imageStream = repositoryService.getResourceAsStream(processDefinition.getDeploymentId(),
                     processDefinition.getDiagramResourceName());
        }
        if(imageStream!=null)
        	IOUtils.copy(imageStream, response.getOutputStream());
    }
	
	private List<String> getHighLightedFlows(ProcessDefinitionEntity processDefinition, String processInstanceId) {
        List<String> highLightedFlows = new ArrayList<String>();
        List<HistoricActivityInstance> historicActivityInstances = historyService
                .createHistoricActivityInstanceQuery()
                .processInstanceId(processInstanceId)
                .orderByHistoricActivityInstanceStartTime().asc().list();

        List<String> historicActivityInstanceList = new ArrayList<String>();
        for (HistoricActivityInstance hai : historicActivityInstances) {
            historicActivityInstanceList.add(hai.getActivityId());
        }

        // add current activities to list
        List<String> highLightedActivities = runtimeService.getActiveActivityIds(processInstanceId);
        historicActivityInstanceList.addAll(highLightedActivities);

        // activities and their sequence-flows
        for (ActivityImpl activity : processDefinition.getActivities()) {
            int index = historicActivityInstanceList.indexOf(activity.getId());

            if (index >= 0 && index + 1 < historicActivityInstanceList.size()) {
                List<PvmTransition> pvmTransitionList = activity
                        .getOutgoingTransitions();
                for (PvmTransition pvmTransition : pvmTransitionList) {
                    String destinationFlowId = pvmTransition.getDestination().getId();
                    if (destinationFlowId.equals(historicActivityInstanceList.get(index + 1))) {
                        highLightedFlows.add(pvmTransition.getId());
                    }
                }
            }
        }
        return highLightedFlows;
    }
	
	
	@RequestMapping(value = "/procinst/updateState")
	@ResponseBody
    public Object updateState(String procinstId,boolean state) 
	{
		Result res=new Result();
		if(state)
			runtimeService.activateProcessInstanceById(procinstId);
		else
			runtimeService.suspendProcessInstanceById(procinstId);
        res.setResult(procinstId);
        return res;
    }
	
	@RequestMapping(value = "/procinst/deleteR")
	@ResponseBody
    public Object deleteR(String procinstId) 
	{
		Result res=new Result();
		runtimeService.deleteProcessInstance(procinstId, "用户管理页面删除流程实例");
        res.setResult(procinstId);
        return res;
    }
	
	@RequestMapping(value = "/procinst/deleteH")
	@ResponseBody
    public Object deleteH(String procinstId) 
	{
		Result res=new Result();
		historyService.deleteHistoricProcessInstance(procinstId);
        res.setResult(procinstId);
        return res;
    }
	
	//流程定义名，历时，结束原因，
	@RequestMapping(value = "/procinst/listH")
    @ResponseBody
    public Object listH(@RequestBody DTRequestParam dtRequestParam) 
    {
    	HistoricProcessInstanceQuery query=historyService.createHistoricProcessInstanceQuery();
    	String searchStr=dtRequestParam.getSearch().getValue();
    	if(!StringUtils.isEmpty(searchStr))
    		query.processInstanceNameLike("%"+searchStr+"%");
    	query.finished();
    	List<HistoricProcessInstance> list=query.orderByProcessInstanceId().desc()
    			.listPage(dtRequestParam.getStart(),dtRequestParam.getLength());
    	
    	Set<String> procdefIds=new HashSet<String>();
    	Set<String> userIds=new HashSet<String>();
    	for(HistoricProcessInstance e:list)
    	{
    		procdefIds.add(e.getProcessDefinitionId());
    		userIds.add(e.getStartUserId());
    	}
    	
    	List<ProcessDefinition> procdefs=repositoryService.createProcessDefinitionQuery().processDefinitionIds(procdefIds).list();
    	Map<String,String> procdefIdName=new HashMap<String, String>(); 
    	for(ProcessDefinition e:procdefs)
    		procdefIdName.put(e.getId(),e.getName());
    	
    	List<Map<String,Object>> res=new ArrayList<Map<String,Object>>();
    	Map<String,Object> item;
    	for(HistoricProcessInstance e:list)
    	{
    		item=new HashMap<String, Object>();
    		item.put("id", e.getId());
    		item.put("name", e.getName());
    		item.put("startTime", e.getStartTime());
    		item.put("endTime", e.getEndTime());
    		item.put("startUserId", e.getStartUserId());
    		item.put("processDefinitionName", procdefIdName.get(e.getProcessDefinitionId()));
    		item.put("processDefinitionId", e.getProcessDefinitionId());
    		item.put("deleteReason", e.getDeleteReason());
    		item.put("duration", e.getDurationInMillis()==null?"":e.getDurationInMillis()/1000);
    		res.add(item);
    	}
    	Long total=query.count();
    	return new DTResponseData(res, total, dtRequestParam.getDraw());
    }
	
    @RequestMapping(value = "/procinst/listR")
    @ResponseBody
    public Object listR(@RequestBody DTRequestParam dtRequestParam) 
    {
    	ProcessInstanceQuery query=runtimeService.createProcessInstanceQuery();
    	String searchStr=dtRequestParam.getSearch().getValue();
    	if(!StringUtils.isEmpty(searchStr))
    		query.processInstanceNameLike("%"+searchStr+"%");
    	List<ProcessInstance> list=query.orderByProcessInstanceId().desc()
    			.listPage(dtRequestParam.getStart(),dtRequestParam.getLength());
    	
    	List<String> procinstIds=new ArrayList<String>();
    	for(ProcessInstance procinst:list)
    		procinstIds.add(procinst.getProcessInstanceId());
    	
    	List<Task> tasks=taskService.createTaskQuery().processInstanceIdIn(procinstIds).list();
    	Map<String,String> procinstTask=new HashMap<String, String>(); 
    	for(Task task:tasks)
    		procinstTask.put(task.getProcessInstanceId(), task.getName());
    		
    	List<Map<String,Object>> res=new ArrayList<Map<String,Object>>();
    	Map<String,Object> item;
    	for(ProcessInstance procinst:list)
    	{
    		item=new HashMap<String, Object>();
    		item.put("id", procinst.getId());
    		item.put("name", procinst.getName());
    		item.put("processDefinitionName", procinst.getProcessDefinitionName());
    		item.put("processDefinitionVersion", procinst.getProcessDefinitionVersion());
    		item.put("suspended", procinst.isSuspended()?"挂起":"活动");
    		item.put("suspendedCode", procinst.isSuspended());
    		item.put("activityId", procinst.getActivityId());
    		item.put("activity", procinstTask.get(procinst.getId()));
    		res.add(item);
    	}
    	Long total=query.count();
    	return new DTResponseData(res, total, dtRequestParam.getDraw());
    }
}
